package ez

import (
	"context"
	"fmt"
	"gitee.com/dreamwood/ez-go/tools"
	"go.mongodb.org/mongo-driver/mongo"
	"runtime"
	"sync"
	"time"
)

// 文件日志
type MongoLogger struct {
	Prefix     string
	TraceDepth int //跟踪起始深度
	DumpDepth  int //追踪深度
	// UseBuffer 是否延迟写入
	UseBuffer     bool
	BufferSize    int //批量写入数据量上限
	WriteInterval time.Duration
	buffers       []interface{}
	lock          *sync.Mutex
	DocName       string
	Collection    *mongo.Collection
}

func NewMongoLogger() *MongoLogger {
	fl := &MongoLogger{
		BufferSize:    1000,
		Prefix:        "[EZ]",
		buffers:       make([]interface{}, 0),
		lock:          &sync.Mutex{},
		TraceDepth:    1,
		DumpDepth:     0,
		WriteInterval: 1 * time.Second,
		DocName:       `EzLogDoc`,
	}
	if DBMongo != nil {
		fl.Collection = DBMongo.Collection(fl.DocName)
	}
	return fl
}

func (this *MongoLogger) StartAutoSave() {
	for {
		time.Sleep(this.WriteInterval)
		//写入数据
		this.lock.Lock()
		if len(this.buffers) > 0 {
			_, e := this.Collection.InsertMany(context.TODO(), this.buffers)
			PrintError(e)
			this.buffers = make([]interface{}, 0)
		}
		this.lock.Unlock()
	}
}

type LogDoc struct {
	Content string
	Trace   string
	Dumps   []string
}

func (this *MongoLogger) Write(data string) {
	doc := LogDoc{
		Content: data,
	}
	pc, f, l, _ := runtime.Caller(this.TraceDepth)
	doc.Trace = fmt.Sprintf("%s %s %s:%d FUNC:%s",
		this.Prefix,
		tools.GetDateYMDHIS("-", ":", " "),
		f, l, runtime.FuncForPC(pc).Name(),
	)
	//添加dump信息
	rightArrow := ""
	if this.DumpDepth > 0 {
		doc.Dumps = make([]string, 0)
		for i := 0; i < this.DumpDepth; i++ {
			pc, f, l, _ = runtime.Caller(this.TraceDepth + i + 1)
			if f == "" {
				break
			}
			rightArrow += "->"
			doc.Dumps = append(doc.Dumps, fmt.Sprintf("%s %s %s %s:%d FUNC:%s",
				this.Prefix,
				tools.GetDateYMDHIS("-", ":", " "),
				rightArrow,
				f, l, runtime.FuncForPC(pc).Name(),
			))
		}
	}
	if this.UseBuffer {
		//根据压力决定写入的
		//压力算法
		this.lock.Lock()
		this.buffers = append(this.buffers, &doc)
		if len(this.buffers) > this.BufferSize {
			//超量就要写入数据库
			_, e := this.Collection.InsertMany(context.TODO(), this.buffers)
			PrintError(e)
			this.buffers = make([]interface{}, 0)
		}
		this.lock.Unlock()

	} else {
		_, e := this.Collection.InsertOne(context.TODO(), doc)
		PrintError(e)
	}

}
